import Tkinter


def drawBox(canva, cor, r, fill="#000000"):
    x, y = cor
    canva.create_rectangle(x, y, x+r, y+r, fill=fill)

class ScrollableCanva(Tkinter.Canvas):

    def __init__(self, root, widget, actual):
        self.tooltip = "0000"
        widget_width, widget_height = widget
        actual_width, actual_height = actual
        actual_width, actual_height = max(actual_width, widget_width),\
                                      max(actual_height, widget_height)
        
        #super(Tkinter.Canvas, self).
        Tkinter.Canvas.__init__(self, root,bg='white',
                               width=widget_width, #width=max(startx*2+m*r, 600), #600
                               height=widget_height, #height=max(starty*2+n*r, 480), #480
                               scrollregion=(0, 0, actual_width, actual_height),
                               )
    
        self.grid(row=0, column=0)

        scrollY = Tkinter.Scrollbar(root, orient=Tkinter.VERTICAL,
                                    command = self.yview)
        #scrollY.grid(row=0, column=1, sticky=Tkinter.N+Tkinter.S)
        scrollY.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)

        scrollX = Tkinter.Scrollbar(root, orient=Tkinter.HORIZONTAL,
                                    command = self.xview)
        #scrollX.grid(row=1, column=0, sticky=Tkinter.E+Tkinter.W, )
        scrollX.pack(side=Tkinter.BOTTOM, fill=Tkinter.X)

        self["xscrollcommand"] = scrollX.set
        self["yscrollcommand"] = scrollY.set

        
        def xy_motion(event):
            x, y = event.x, event.y
            #print x, y
            #print canva.canvasx(x), canva.canvasy(y)
            self.tooltip = "%d %d" % (self.canvasx(x), self.canvasy(y))
            
            if x < 30:        
                delta = -1
                #canva.xview('scroll', delta, 'units')

            if x > (widget_width - 30):
                delta = 1
                #canva.xview('scroll', delta, 'units')

            if y < 30:
                delta = -1
                #canva.yview('scroll', delta, 'units')

            if y > (widget_height - 30):
                delta = 1
                #canva.yview('scroll', delta, 'units')
                
        self.bind('<Motion>', xy_motion)

        self.pack()

### mapping & mappingMatrix provide a solution to the color-value mapping strategy
def mapping(alist):
    mmax = max(alist)
    mmin = min(alist)
    mcolor = []
    for i in alist:
        c = 255 - int(255 * (i-mmin)/float(mmax-mmin))
        k = hex(c)[2:]
        if len(k) == 1: k = "0"+k
        mcolor.append(k)
    return mcolor
        
def mappingMatrix(matrix):
    s = []
    for i in matrix: s += i
    mm = mapping(s)
    s, start = [], 0
    for i in matrix:
        s.append(mm[start:start+len(i)])
        start += len(i)
    return s

"""
def drawList(root, alist, mapping=mapping, startx=5, starty=5, r=20):
    n = len(alist)
    canva = Tkinter.Canvas(root,bg='white',width=600,height=480)
    canva.pack()
    sx, sy= startx, starty
    mm = mapping(alist)
    for i in xrange(n):
        drawBox(canva, (sx, sy), r, "#"+(mm[i]*3))
        sx, sy = sx+r, sy
"""
def drawList(root, alist, mappingFun=mappingMatrix, width=800, height=600, startx=5, starty=5, r=20):
    drawMatrix(root, [alist], mappingFun, width, height, startx, starty, r)
    
def drawMatrix(root, matrix, mappingFun=mappingMatrix, width=800, height=600, startx=5, starty=5, r=20):
    n, m = len(matrix),  max([len(i) for i in matrix])
    sx, sy= startx, starty
    mm = mappingFun(matrix)

    actual_width, actual_height = startx*2+m*r, starty*2+n*r
    widget_width, widget_height = width, height
    if width > actual_width: widget_width = actual_width
    if height > widget_height: widget_height = actual_height
    
    canva = ScrollableCanva(root,
                         (widget_width, widget_height),
                         (actual_width, actual_height))

    for i in xrange(n):
        for j in xrange(m):
            drawBox(canva, (sx, sy), r, "#"+(mm[i][j]*3))
            sx += r
        sy += r
        sx = startx

    import lxtk
    # Must after the canva.pack()
    def getMsg():
        a, b = canva.tooltip.split(" ")
        a, b = int(a), int(b)
        a, b = (a-startx)/r, (b-starty)/r
        if (a<0)or(b<0): return "None"
        #return "<html>[%d, %d]: " % (b, a) + "<b>" + str(matrix[b][a]) + "</b></html>"
        return "[%d, %d]: " % (b, a) + str(matrix[b][a])
    lxtk.ToolTip(canva, msg=None, msgFunc=getMsg, follow=True, delay=0)


def mainApp():
    root=Tkinter.Tk()
    #drawList(root, [1,2,3])
    drawMatrix(root, [range(30)] * 30, width=400, height=300)
    print "Main"
    root.mainloop()

def mainApp0():
    root=Tkinter.Frame()
    root.master.title("Example")
    root.grid(sticky=Tkinter.N+Tkinter.E+Tkinter.S+Tkinter.W)
    #root.pack()
    #root.grid()
    drawList(root, range(100))
    #drawMatrix(root, [rangere(30)] * 30)
    print "Main"
    root.mainloop()

def independent(app):
    t = threading.Thread(target=app)
    t.setDaemon(0)
    t.start()

import threading
if __name__ == "__main__":
    #mainApp()
    #independent(mainApp0)
    mainApp()
    #independent(mainApp0)
    print "Hi"
